import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockApplication {
    private static int counter = 0;
    private static final Object syncLock = new Object();
    private static final ReentrantLock reentrantLock = new ReentrantLock();
    private static final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private static final Lock readLock = readWriteLock.readLock();
    private static final Lock writeLock = readWriteLock.writeLock();

    public static void main(String[] args) throws InterruptedException {
        // // 1. synchronized演示
        // synchronizedDemo();
        //
        // 2. ReentrantLock可重入锁演示
        // reentrantLockDemo();
        //
        // 3. 读写锁演示
        // readWriteLockDemo();

        // 4. 锁性能对比
        lockPerformanceComparison();
    }

    /**
     * synchronized演示
     */
    private static void synchronizedDemo() throws InterruptedException {
        System.out.println("=== synchronized演示 ===");

        // 对象锁演示
        SynchronizedExample example = new SynchronizedExample();

        Thread t1 = new Thread(() -> example.synchronizedMethod("线程1"), "Thread-1");
        Thread t2 = new Thread(() -> example.synchronizedMethod("线程2"), "Thread-2");

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        // 类锁演示
        Thread t3 = new Thread(() -> SynchronizedExample.staticSynchronizedMethod("线程3"), "Thread-3");
        Thread t4 = new Thread(() -> SynchronizedExample.staticSynchronizedMethod("线程4"), "Thread-4");

        t3.start();
        t4.start();
        t3.join();
        t4.join();

        // 代码块锁演示
        Thread t5 = new Thread(() -> example.synchronizedBlock("线程5"), "Thread-5");
        Thread t6 = new Thread(() -> example.synchronizedBlock("线程6"), "Thread-6");

        t5.start();
        t6.start();
        t5.join();
        t6.join();

        System.out.println();
    }

    /**
     * ReentrantLock演示
     */
    private static void reentrantLockDemo() throws InterruptedException {
        System.out.println("=== ReentrantLock演示 ===");

        // 基本使用
        ReentrantLockExample lockExample = new ReentrantLockExample();

        Thread t1 = new Thread(() -> lockExample.lockMethod("线程1"), "Thread-1");
        Thread t2 = new Thread(() -> lockExample.lockMethod("线程2"), "Thread-2");

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        // 可中断锁演示
        Thread t3 = new Thread(() -> {
            try {
                lockExample.interruptibleLockMethod("线程3");
            } catch (InterruptedException e) {
                System.out.println("线程3被中断");
            }
        }, "Thread-3");

        Thread t4 = new Thread(() -> {
            try {
                lockExample.interruptibleLockMethod("线程4");
            } catch (InterruptedException e) {
                System.out.println("线程4被中断");
            }
        }, "Thread-4");

        t3.start();
        Thread.sleep(100);  // 确保t3先获取锁
        t4.start();
        Thread.sleep(1000); // 等待一段时间后中断t4
        t4.interrupt();

        t3.join();
        t4.join();

        // 超时获取锁演示
        Thread t5 = new Thread(() -> lockExample.tryLockWithTimeout("线程5"), "Thread-5");
        Thread t6 = new Thread(() -> lockExample.tryLockWithTimeout("线程6"), "Thread-6");

        t5.start();
        t6.start();
        t5.join();
        t6.join();

        System.out.println();
    }

    /**
     * 读写锁演示
     */
    private static void readWriteLockDemo() throws InterruptedException {
        System.out.println("=== 读写锁演示 ===");

        ReadWriteLockExample rwExample = new ReadWriteLockExample();

        // 启动多个读线程
        Thread[] readers = new Thread[3];
        for (int i = 0; i < 3; i++) {
            final int index = i;
            readers[i] = new Thread(() -> rwExample.read("读线程" + index), "Reader-" + index);
        }

        // 启动一个写线程
        Thread writer = new Thread(() -> rwExample.write("写线程", "新数据"), "Writer");

        // 先启动读线程
        for (Thread reader : readers) {
            reader.start();
        }

        Thread.sleep(1000);

        // 再启动写线程
        writer.start();

        // 等待所有线程完成
        for (Thread reader : readers) {
            reader.join();
        }
        writer.join();

        System.out.println();
    }

    /**
     * 锁性能对比
     */
    private static void lockPerformanceComparison() throws InterruptedException {
        System.out.println("=== 锁性能对比 ===");

        int threadCount = 10;
        int iterations = 100000;

        // synchronized性能测试
        counter = 0;
        long startTime = System.currentTimeMillis();

        Thread[] syncThreads = new Thread[threadCount];
        for (int i = 0; i < threadCount; i++) {
            syncThreads[i] = new Thread(() -> {
                for (int j = 0; j < iterations; j++) {
                    synchronized (syncLock) {
                        counter++;
                    }
                }
            });
            syncThreads[i].start();
        }

        for (Thread thread : syncThreads) {
            thread.join();
        }

        long syncTime = System.currentTimeMillis() - startTime;
        System.out.println("synchronized耗时: " + syncTime + "ms, 结果: " + counter);

        // ReentrantLock性能测试
        counter = 0;
        startTime = System.currentTimeMillis();

        Thread[] lockThreads = new Thread[threadCount];
        for (int i = 0; i < threadCount; i++) {
            lockThreads[i] = new Thread(() -> {
                for (int j = 0; j < iterations; j++) {
                    reentrantLock.lock();
                    try {
                        counter++;
                    } finally {
                        reentrantLock.unlock();
                    }
                }
            });
            lockThreads[i].start();
        }

        for (Thread thread : lockThreads) {
            thread.join();
        }

        long lockTime = System.currentTimeMillis() - startTime;
        System.out.println("ReentrantLock耗时: " + lockTime + "ms, 结果: " + counter);

        System.out.println("性能比较: synchronized vs ReentrantLock = " +
                syncTime + "ms vs " + lockTime + "ms");

        System.out.println();
    }
}

/**
 * synchronized示例类
 */
class SynchronizedExample {
    private int value = 0;

    // 同步方法（对象锁）
    public synchronized void synchronizedMethod(String threadName) {
        System.out.println(threadName + " 进入同步方法");
        try {
            Thread.sleep(2000);
            value++;
            System.out.println(threadName + " 执行完成，value = " + value);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    // 静态同步方法（类锁）
    public static synchronized void staticSynchronizedMethod(String threadName) {
        System.out.println(threadName + " 进入静态同步方法");
        try {
            Thread.sleep(2000);
            System.out.println(threadName + " 静态方法执行完成");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    // 同步代码块
    public void synchronizedBlock(String threadName) {
        synchronized (this) {
            System.out.println(threadName + " 进入同步代码块");
            try {
                Thread.sleep(2000);
                value++;
                System.out.println(threadName + " 代码块执行完成，value = " + value);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

/**
 * ReentrantLock示例类
 */
class ReentrantLockExample {
    private final ReentrantLock lock = new ReentrantLock();
    private int value = 0;

    // 基本锁使用
    public void lockMethod(String threadName) {
        lock.lock();
        try {
            System.out.println(threadName + " 获取到锁");
            Thread.sleep(2000);
            value++;
            System.out.println(threadName + " 执行完成，value = " + value);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
            System.out.println(threadName + " 释放锁");
        }
    }

    // 可中断锁
    public void interruptibleLockMethod(String threadName) throws InterruptedException {
        lock.lockInterruptibly();  // 可中断的锁获取
        try {
            System.out.println(threadName + " 获取到可中断锁");
            Thread.sleep(3000);
            System.out.println(threadName + " 可中断锁执行完成");
        } finally {
            lock.unlock();
            System.out.println(threadName + " 释放可中断锁");
        }
    }

    // 超时获取锁
    public void tryLockWithTimeout(String threadName) {
        try {
            if (lock.tryLock(1, TimeUnit.SECONDS)) {  // 尝试1秒内获取锁
                try {
                    System.out.println(threadName + " 在超时时间内获取到锁");
                    Thread.sleep(2000);
                    System.out.println(threadName + " 超时锁执行完成");
                } finally {
                    lock.unlock();
                    System.out.println(threadName + " 释放超时锁");
                }
            } else {
                System.out.println(threadName + " 获取锁超时");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

/**
 * 读写锁示例类
 */
class ReadWriteLockExample {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    private String data = "初始数据";

    // 读操作
    public void read(String threadName) {
        readLock.lock();
        try {
            System.out.println(threadName + " 开始读取数据");
            Thread.sleep(2000);  // 模拟读取耗时
            System.out.println(threadName + " 读取到数据: " + data);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            readLock.unlock();
            System.out.println(threadName + " 释放读锁");
        }
    }

    // 写操作
    public void write(String threadName, String newData) {
        writeLock.lock();
        try {
            System.out.println(threadName + " 开始写入数据");
            Thread.sleep(3000);  // 模拟写入耗时
            data = newData;
            System.out.println(threadName + " 写入完成: " + data);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            writeLock.unlock();
            System.out.println(threadName + " 释放写锁");
        }
    }
}
